package com.cw.utils.java.caffeine;

import com.github.benmanes.caffeine.cache.*;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * Population（缓存类型）
 */
public class Population {

    //1.Cache
    private static void manual() {
        // 构建caffeine的缓存对象，并指定在写入后的10分钟内有效，且最大允许写入的条目数为10000
        Cache<String, String> cache = Caffeine.newBuilder()
                .expireAfterWrite(10, TimeUnit.MINUTES)
                .maximumSize(10_000)
                .build();
        String key = "hello";
        // 查找某个缓存元素，若找不到则返回null
        String str = cache.getIfPresent(key);
        System.out.println("cache.getIfPresent(key) ---> " + str);
        // 查找某个缓存元素，若找不到则调用函数生成，如无法生成则返回null
        str = cache.get(key, k -> create(key));
        System.out.println("cache.get(key, k -> create(key)) ---> " + str);
        // 添加或者更新一个缓存元素
        cache.put(key, str);
        System.out.println("cache.put(key, str) ---> " + cache.getIfPresent(key));
        // 移除一个缓存元素
        cache.invalidate(key);
        System.out.println("cache.invalidate(key) ---> " + cache.getIfPresent(key));
    }

    private static String create(Object key) {
        return key + " world";
    }

    //2.Loading
    /**
     * LoadingCache是附加在CacheLoader之上构建的缓存对象。
     * 可以使用getAll方法执行批量查找，默认情况下，getAll()方法会单独调用CacheLoader.load()方法来加载每个不在缓存中的Key，
     * 必要情况下可以重写CacheLoader.loadAll()方法来弥补其缺陷。
     */
    public static void loading() {
        LoadingCache<String, String> cache = Caffeine.newBuilder()
                .maximumSize(10_000)
                .expireAfterWrite(10, TimeUnit.MINUTES)
                .build(key -> create(key)); // 当调用get或者getAll时，若找不到缓存元素，则会统一调用create(key)生成
        String key = "hello";
        String str = cache.get(key);
        System.out.println("cache.get(key) ---> " + str);
        List<String> keys = Arrays.asList("a", "b", "c", "d", "e");
        // 批量查找缓存元素，如果缓存不存在则生成缓存元素
        Map<String, String> maps = cache.getAll(keys);
        System.out.println("cache.getAll(keys) ---> " + maps);
    }

    //3.Asynchronous (Manual)
    /**
     * AsyncCache就是Cache的异步实现方式，提供了通过Executor生成缓存元素并返回CompletableFuture的能力。
     * synchronous()提供了在缓存计算完成前的阻塞能力，AsyncCache默认使用ForkJoinPool.commonPool()线程池，
     * 你也可以通过重写Caffeine.executor(executor)来实现自己的线程池。
     */
    private static void asynchronous() {
        AsyncCache<String, String> cache = Caffeine.newBuilder()
                .expireAfterWrite(10, TimeUnit.MINUTES)
                .maximumSize(10_000)
                .buildAsync();
        String key = "Hello";
        // 查找某个缓存元素，若找不到则返回null
        CompletableFuture<String> value = cache.getIfPresent(key);
        // 查找某个缓存元素，若不存在则异步调用create方法生成
        value = cache.get(key, k -> create(key));
        // 添加或者更新一个缓存元素
        cache.put(key, value);
        // 移除一个缓存元素
        cache.synchronous().invalidate(key);
    }

    //4.Asynchronously Loading
    /**
     * AsyncLoadingCache就是LoadingCache的异步形式
     */
    private static void asynchronouslyLoading() {
        AsyncLoadingCache<String, String> cache = Caffeine.newBuilder()
                .maximumSize(10_000)
                .expireAfterWrite(10, TimeUnit.MINUTES)
                // 异步构建一个同步的调用方法create(key)
                .buildAsync(key -> create(key));
        // 也可以使用下面的方式来异步构建缓存，并返回一个future
        // .buildAsync((key, executor) -> createAsync(key, executor));
        String key = "Hello";
        // 查找某个缓存元素，若找不到则会异步生成。
        CompletableFuture<String> value = cache.get(key);
        List<String> keys = Arrays.asList("a", "b", "c", "d", "e");
        // 批量查找某些缓存元素，若找不到则会异步生成。
        CompletableFuture<Map<String, String>> graphs = cache.getAll(keys);
    }

}
